package com.github.livebase.event;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.github.livebase.log.Logger;
import com.github.livebase.util.base.CollectionsUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName EventDispatcher
 * @description:
 * @author: biao532
 * @create: 2023-12-25 19:14
 * @Version 1.0
 **/
public class EventDispatcherImpl implements EventDispatcher {
    private class EventListenerWrap implements EventListener{
        private boolean async;
        private EventListener eventListener;
        private EventListenerWrap(boolean async, @NonNull EventListener listener) {
            this.async = async;
            this.eventListener = listener;
        }
        @Override
        public boolean equals(@Nullable Object obj) {
            if (obj instanceof EventListenerWrap) {
                return eventListener.equals(((EventListenerWrap)obj).eventListener);
            }
            if (obj instanceof EventListener) {
                return eventListener.equals(obj);
            }
            return false;
        }

        @Override
        public void onEvent(Event event) {
            eventListener.onEvent(event);
        }
    }
    public static final EventDispatcher EMPTY = new EventDispatcher() {
        @Override
        public boolean register(EventListener listener, boolean async) {
            return false;
        }
        @Override
        public void dispatch(Event data) {

        }
        @Override
        public void unregister(EventListener listener) {

        }
        @Override
        public void destroy() {

        }
        @Override
        public String getEventId() {
            return null;
        }
        @Override
        public void addDestroyListener(DestroyListener listener) {

        }
        @Override
        public void removeDestroyListener(DestroyListener listener) {

        }
    };
    private List<EventListenerWrap> listeners;
    private String eventId;
    private Logger logger;
    private List<DestroyListener> destroyListeners;

    public EventDispatcherImpl(String eventId, Logger logger) {
        this.eventId = eventId;
        this.destroyListeners = new ArrayList<>(0);
        listeners = new ArrayList<>();
        this.logger = logger;
    }
    public void addDestroyListener(DestroyListener listener) {
        destroyListeners.add(listener);
    }
    public void removeDestroyListener(DestroyListener listener) {
        destroyListeners.remove(listener);
    }

    public String getEventId() {
        return eventId;
    }

    @Override
    public boolean register(EventListener listener, boolean async) {
        if (listeners.contains(listener)) {
            return false;
        }
        logger.debug("EventDispatcherImpl", "register listener[{}] eventId[{}]", listener, eventId);
        listeners.add(new EventListenerWrap(async, listener));
        return true;
    }

    @Override
    public void dispatch(Event event) {
        if (!eventId.equals(event.getEventId())) {
            return;
        }
        logger.debug("EventDispatcherImpl","event dispatch eventId = {}", eventId);
        for (EventListenerWrap wrap : listeners) {
            logger.trance("EventDispatcherImpl","event dispatch eventId[{}] listener[{}] async[{}]", eventId, wrap.eventListener, wrap.async);
            if (wrap.async) {
                SimpleEventBus.getExecutor().submit( ()-> wrap.onEvent(event));
                continue;
            }
            wrap.onEvent(event);
        }
    }

    @Override
    public void unregister(EventListener listener) {
        listeners.remove(new EventListenerWrap(true, listener));
        logger.debug("EventDispatcherImpl","unregister eventId[{}] listener[{}]", eventId, listener);
    }

    @Override
    public void destroy() {
        CollectionsUtil.foreach(destroyListeners, (d) -> {
            d.onDestroy(this);
        });
        listeners.clear();
        destroyListeners.clear();
    }
}
